package com.xwn.utils.core;

import com.alibaba.druid.util.Base64;
import org.apache.commons.lang3.StringUtils;

import javax.crypto.*;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;

/**
 *
 * @Author duandw
 * @Date 2019/12/31 17:36
 **/
public class CipherUtilsImpl {
    private static String key;
    private static String keyForPw;
    private static String iv;
    private static final String dk = "rk.=278ZAmb~0&]F";

    public CipherUtilsImpl() {
    }

    public static String cipher(String value) throws NoSuchPaddingException, InvalidKeyException, NoSuchAlgorithmException, IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException {
        return new String(jiami(base64EncryptByAes128(value, getKey()).toCharArray(), 7));
    }

    public static String decipher(String value) throws NoSuchPaddingException, NoSuchAlgorithmException, IllegalBlockSizeException, BadPaddingException, InvalidKeyException, IOException {
        char[] encodeStr = jiemi(value.toCharArray(), 7);
        return base64DecryptByAes128(new String(encodeStr), getKey());
    }

    public static String base64EncryptByAes128(String content, String pw) throws NoSuchPaddingException, BadPaddingException, NoSuchAlgorithmException, IllegalBlockSizeException, UnsupportedEncodingException, InvalidKeyException {
        return !StringUtils.isBlank(content) && !StringUtils.isBlank(pw) ? Base64.byteArrayToBase64(encryptByAes128(content, pw)) : null;
    }

    public static byte[] encryptByAes128(String content, String pw) throws NoSuchAlgorithmException, NoSuchPaddingException, UnsupportedEncodingException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
        KeyGenerator kgen = KeyGenerator.getInstance("AES");
        kgen.init(128, new SecureRandom(pw.getBytes()));
        SecretKey secretKey = kgen.generateKey();
        byte[] enCodeFormat = secretKey.getEncoded();
        SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");
        Cipher cipher = Cipher.getInstance("AES");
        byte[] byteContent = content.getBytes("utf-8");
        cipher.init(1, key);
        byte[] result = cipher.doFinal(byteContent);
        return result;
    }

    public static String encryptByIosAES(String content, String key) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, UnsupportedEncodingException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException {
        byte[] byteContent = content.getBytes("UTF-8");
        return encryptByIosAES(byteContent, key);
    }

    public static String encryptByIosAES(byte[] byteContent, String key) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException {
        byte[] encryptedBytes = byteEncryptByIosAES(key, byteContent);
        return Base64.byteArrayToBase64(encryptedBytes);
    }

    public static byte[] byteEncryptByIosAES(String key, byte[] byteContent) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException {
        byte[] enCodeFormat = key.getBytes();
        SecretKeySpec secretKeySpec = new SecretKeySpec(enCodeFormat, "AES");
        byte[] initParam = getIv().getBytes();
        IvParameterSpec ivParameterSpec = new IvParameterSpec(initParam);
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(1, secretKeySpec, ivParameterSpec);
        return cipher.doFinal(byteContent);
    }

    public static String decryptByIosAES(String content, String key) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException, IOException {
        byte[] encryptedBytes = Base64.base64ToByteArray(content);
        byte[] result = byteDecryptByIosAES(key, encryptedBytes);
        return new String(result, "UTF-8");
    }

    public static byte[] byteDecryptByIosAES(String key, byte[] encryptedBytes) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException {
        byte[] enCodeFormat = key.getBytes();
        SecretKeySpec secretKey = new SecretKeySpec(enCodeFormat, "AES");
        byte[] initParam = getIv().getBytes();
        IvParameterSpec ivParameterSpec = new IvParameterSpec(initParam);
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(2, secretKey, ivParameterSpec);
        return cipher.doFinal(encryptedBytes);
    }

    public static String base64DecryptByAes128(String content, String pw) throws NoSuchPaddingException, NoSuchAlgorithmException, IllegalBlockSizeException, BadPaddingException, InvalidKeyException, IOException {
        return !StringUtils.isBlank(content) && !StringUtils.isBlank(pw) ? decryptByAes128(content, pw) : null;
    }

    public static String decryptByAes128(String value, String pw) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, IOException {
        byte[] content = Base64.base64ToByteArray(value);
        KeyGenerator kgen = KeyGenerator.getInstance("AES");
        kgen.init(128, new SecureRandom(pw.getBytes()));
        SecretKey secretKey = kgen.generateKey();
        byte[] enCodeFormat = secretKey.getEncoded();
        SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");
        Cipher cipher = Cipher.getInstance("AES");
        cipher.init(2, key);
        byte[] result = cipher.doFinal(content);
        return new String(result, "UTF-8");
    }

    public static char[] jiami(char[] str, int n) {
        int len = str.length;
        int d;
        if ((d = len % n) != 0) {
            len = len + n - d;
        }

        char[] temp = new char[len];
        int m = len / n;

        int i;
        for(i = 0; i < m; ++i) {
            for(int j = 0; j < n; ++j) {
                if (i * n + j < str.length) {
                    temp[i + m * j] = str[i * n + j];
                } else {
                    temp[i + m * j] = ' ';
                }
            }
        }

        while(temp[len - 1] == ' ') {
            --len;
        }

        char[] miwen = new char[len];

        for(i = 0; i < len; ++i) {
            miwen[i] = temp[i];
        }

        return miwen;
    }

    public static char[] jiemi(char[] miwen, int n) {
        int len = miwen.length;
        int d;
        if ((d = len % n) != 0) {
            len = len + n - d;
        }

        char[] temp = new char[len];
        int m = len / n;

        int i;
        for(i = 0; i < n; ++i) {
            for(int j = 0; j < m; ++j) {
                if (i * m + j < miwen.length) {
                    temp[i + j * n] = miwen[i * m + j];
                } else {
                    temp[i + n * j] = ' ';
                }
            }
        }

        while(temp[len - 1] == ' ') {
            --len;
        }

        char[] str = new char[len];

        for(i = 0; i < len; ++i) {
            str[i] = temp[i];
        }

        return str;
    }

    public static String getKey() {
        return key;
    }

    public void setKey(String key) {
        key = key;
    }

    public static String getKeyForPw() {
        return keyForPw == null ? "9876543210fedcba" : keyForPw;
    }

    public void setKeyForPw(String keyForPw) {
        keyForPw = keyForPw;
    }

    public static String getIv() {
        return iv == null ? "1234567890abcdef" : iv;
    }

    public static void setStaticIv(String iv) {
        iv = iv;
    }

    public void setIv(String iv) {
        setStaticIv(iv);
    }

    public static String getDk() {
        return "rk.=278ZAmb~0&]F";
    }
}
